Concurrent execution of multiple instances of code has become commonplace across many varieties of computing devices. Processor components incorporating multiple cores that simultaneously execute instances of code, once found only in servers, have become common in personal and embedded computing devices. While such concurrent execution of code enables greater processing performance, it also creates the need to address issues of synchronizing execution to enable sharing of resources in a manner that avoids instances of contention over those resources. Specifically, concurrently executed instances of either the same or different code may require access to the same resource (e.g., a piece of data, an input/output component, etc.) in a manner in which the state of that resource may be changed during that access by at least one of those instances. Problems can arise where the state of that resource is modified by one instance of code during its access in a manner that causes unpredictable behavior by another instance of code that concurrently accesses that same resource.
A common solution to preventing contention over a resource is locking access to that resource to just one instance of code at a time. An instance of code incorporates a lock instruction to lock access to a resource to prevent other instances of either the same code or different code from accessing that same resource as it does so. This enables that instance of code to read and/or modify the state of that resource as needed without interference from other instances of code. Upon completion of its access to that resource, the resource is unlocked to permit access by other instances of either the same or different code.
Unfortunately, while locking of resources is effective in preventing instances of contention, locking can substantially negate the processing performance advantages of concurrent execution of code. Specifically, the locking of a resource can effectively forestall further execution of other instances of code throughout the time that resource remains locked. Further, such locking may not always be necessary as there are frequently instances in which accesses to a resource by multiple instances of the same or different code may be of a nature that does not change the state of that resource such that instances of contention would not occur. Thus, there are frequent occasions in which resources are locked unnecessarily.
A developing solution to such unnecessary locking is speculative execution of code accessing the same resource. Following receipt by a processor component of an indication of one instance of code seeking to lock access to a resource, execution of another instance of either the same or different code is speculatively allowed to proceed such that the other instance is allowed to access that resource in spite of the request to lock access to it. The execution of both instances of code is monitored for the occurrence of an instance of contention. If contention is detected, then the execution of one or both of those instances of code is aborted to the extent necessary to place those instances of code and the resource in a state in which execution can recur in a manner that avoids the instance of contention. Frequently, such recurrence of execution entails repeating execution of the instance of code that originally sought to lock the resource, while not allowing the speculative execution of the other instance of code. Unfortunately, while such speculative execution may alleviate occurrences of unnecessary locking, the aborting of execution of code can also negatively affect processing performance.